/*
 * sender.c
 *
 *  Created on: 2013. 10. 16.
 *      Author: jphong
 */

#include "np.h"
#include "packet.h"

typedef enum {
	Wait_for_call,
	Wait_for_ACK,
	Closing
} State;

extern int DEBUG_ON;	// print debug messages if set
static unsigned int	ReTxTimeout = 100;		// default timeout in msec
static char *localhost = "127.0.0.1";			// default receiver hostname
static char *port = "5678";						// default receiver port

//Packet buffers
static Packet 	sndPacket, rcvPacket;
/*
 * rdt3.0 sender
 */
int main( int argc, char **argv )
{
	struct sockaddr_in peer;
	int 	fd, s;
	unsigned char sndSeq;
	Event 	event;
	State 	state;
	Packet	*sndpkt = &sndPacket;
	Packet *rcvpkt = &rcvPacket;
	char	*data = &(sndPacket.data[0]);
	char	*hostname, *service;
	int 	opt;

	// Command line option processing
	while ( (opt = getopt(argc, argv, "dt:")) != -1) {
		switch (opt) {
		case 'd':
			DEBUG_ON = 1; 	// Debug mode
			break;
		case 't':
			ReTxTimeout = atoi(optarg);
			break;
		default:
			error(1, 0, "Usage: %s [-d] [-t timeout] [<receiver name or IP address> <port number>]\n", argv[0] );
		}
	}
	if (optind == argc-2) {
		hostname = argv[optind];
		service = argv[optind+1];
	} else if (optind == argc) {
		hostname = localhost;
		service = port;
	} else
		error(1, 0, "Usage: %s [-d] [-t timeout] [<receiver name or IP address> <port number>]\n", argv[0] );
	debug("To %s:%s\tTimeout = %dmsec\tDebugMode = %s\n", hostname, service, ReTxTimeout,
			DEBUG_ON ? "on" : "off");

	set_address( hostname, service, &peer, "udp" ); // Set peer's IP and port

	if ( (s = socket( AF_INET, SOCK_DGRAM, 0 )) < 0)
		error(1, errno, "socket creation failed\n" );

	fd = fileno(stdin);

	// Init conditiion
	sndSeq = 0;
	state = Wait_for_call;

	// FSM
	for (;;) {
		int 	datalen, rcvlen;

		event = getEvent(fd, s);
		// Actions taken by State and Event
		switch (state) {
		// Wait_for_call state
		case Wait_for_call:
			switch (event) {
			case RDT_SEND:
				if ( fgets( data, MAX_DATA, stdin) != NULL ) {  // Get data from above
					/*
					 * More codes here ...
					 */
					continue;
				} else {				// EoF encountered. Close the session
					/*
					 * More codes here ...
					 */
				}
			default:
				continue;				// ignore the event
			}
		//Wait_for_ACK state
		case Wait_for_ACK:
			switch (event) {
			case RDT_RCV:
				/*
				 * More codes here ...
				 */
					continue;
			case TIMEOUT:
				/*
				 * More codes here ...
				 */
				continue;
			default:
				continue;
			}
		// Closing state
			// wait an ACK. Sender shall stop when anything hear from receiver
		case Closing:
			switch (event) {
			case RDT_RCV:
				/*
				 * More codes here ...
				 */
			case TIMEOUT:
				/*
				 * More codes here ...
				 */
				continue;
			default:
				continue;
			}	// End of inner switch
		}	// End of outer switch

	}   // End of for loop

}	// End of main

